#ifndef U2MemoryAllocatorConfig_H
#define U2MemoryAllocatorConfig_H

#include "U2PreRequest.h"



namespace U2EG_NAMESPACE_NAME
{
enum MemoryCategory
{
	/// General purpose
	MEMCATEGORY_GENERAL			= 0,
	/// Geometry held in main memory
	MEMCATEGORY_GEOMETRY		= 1, 
	/// Animation data like tracks, bone matrices
	MEMCATEGORY_ANIMATION		= 2, 
	/// Nodes, control data
	MEMCATEGORY_SCENE_CONTROL	= 3,
	/// Scene object instances
	MEMCATEGORY_SCENE_OBJECTS	= 4,
	/// Other resources
	MEMCATEGORY_RESOURCE		= 5,
	/// Scripting
	MEMCATEGORY_SCRIPTING		= 6,
	/// Rendersystem structures
	MEMCATEGORY_RENDERSYS		= 7,

	// sentinel value, do not use 
	MEMCATEGORY_COUNT			= 8
};
}


#include "U2MemoryAllocatedObject.h"


#if U2_MEMORY_ALLOCATOR == U2_MEMORY_ALLOCATOR_STD
#	include "U2MemoryStdAlloc.h"
namespace U2EG_NAMESPACE_NAME
{
	// configure default allocators based on the options above
	// notice how we're not using the memory categories here but still roughing them out
	// in your allocators you might choose to create different policies per category

	// configurable category, for general malloc
	// notice how we ignore the category here
	template <MemoryCategory Cat> class CategorisedAllocPolicy : public U2StdAllocPolicy{};
	template <MemoryCategory Cat, size_t align = 0> class CategorisedAlignAllocPolicy : public U2StdAlignedAllocPolicy<align>{};

	//template <> class CategorisedAllocPolicy<MEMCATEGORY_SCENE_OBJECTS> : public YourSceneObjectAllocPolicy{};
	//template <size_t align> class CategorisedAlignAllocPolicy<MEMCATEGORY_SCENE_OBJECTS, align> : public YourSceneObjectAllocPolicy<align>{};
}
#endif



namespace U2EG_NAMESPACE_NAME
{
	
// Useful shortcuts
typedef CategorisedAllocPolicy<MEMCATEGORY_GENERAL>		    GeneralAllocPolicy;
typedef CategorisedAllocPolicy<MEMCATEGORY_RESOURCE>        ResourceAllocPolicy;
typedef CategorisedAllocPolicy<MEMCATEGORY_RENDERSYS>       RenderSysAllocPolicy;
typedef CategorisedAllocPolicy<MEMCATEGORY_GEOMETRY>        GeometryAllocPolicy;
typedef CategorisedAllocPolicy<MEMCATEGORY_SCENE_OBJECTS>   SceneObjAllocPolicy;
typedef CategorisedAllocPolicy<MEMCATEGORY_SCENE_CONTROL>   SceneCtlAllocPolicy;


// Now define all the base classes for each allocation
typedef U2MemoryAllocatedObject<GeneralAllocPolicy>		GeneralAllocatedObject;
typedef U2MemoryAllocatedObject<ResourceAllocPolicy>    ResourceAllocatedObject;
typedef U2MemoryAllocatedObject<RenderSysAllocPolicy>   RenderSysAllocatedObject;
typedef U2MemoryAllocatedObject<GeometryAllocPolicy>    GeometryAllocatedObject;
typedef U2MemoryAllocatedObject<SceneObjAllocPolicy>    SceneObjAllocatedObject;
typedef U2MemoryAllocatedObject<SceneCtlAllocPolicy>    SceneCtlAllocatedObject;


typedef GeneralAllocatedObject							ArchiveAlloc;
typedef GeneralAllocatedObject							LogAlloc;
typedef GeneralAllocatedObject							DynLibAlloc;
typedef GeneralAllocatedObject							PluginAlloc;
typedef GeneralAllocatedObject							StreamAlloc;
typedef GeneralAllocatedObject                          ConfigAlloc;
typedef ResourceAllocatedObject                         ResourceAlloc;
typedef GeneralAllocatedObject                          CodecAlloc;
typedef GeneralAllocatedObject                          ImageAlloc;
typedef RenderSysAllocatedObject                        BufferAlloc;
typedef RenderSysAllocatedObject                        RenderSysAlloc;
typedef GeometryAllocatedObject                         VertexDataAlloc;
typedef GeometryAllocatedObject		                    IndexDataAlloc;
typedef GeneralAllocatedObject		                    TimerAlloc;
typedef RenderSysAllocatedObject	                    ViewportAlloc;
typedef SceneObjAllocatedObject		                    MovableAlloc;
typedef GeneralAllocatedObject                          UtilityAlloc;
typedef GeneralAllocatedObject                          RootAlloc;
typedef SceneCtlAllocatedObject		                    SceneMgrAlloc;
typedef ResourceAllocatedObject                         TextureUnitStateAlloc;
typedef GeneralAllocatedObject                          ControllerAlloc;

}


namespace U2EG_NAMESPACE_NAME
{
	/** Utility function for constructing an array of objects with placement new,
		without using new[] (which allocates an undocumented amount of extra memory
		and so isn't appropriate for custom allocators).
	*/
	template<typename T>
	T* constructN(T* basePtr, size_t count)
	{
		for (size_t i = 0; i < count; ++i)
		{
			new ((void*)(basePtr+i)) T();
		}
		return basePtr;
	}
}


#if U2_DEBUG > 0
/// Allocate a block of raw memory, and indicate the category of usage
#	define U2_MALLOC(bytes, category)		::U2EG_NAMESPACE_NAME::CategorisedAllocPolicy<category>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)
/// Allocate a block of memory for a primitive type, and indicate the category of usage
#	define U2_ALLOC_T(T, count, category)	static_cast<T*>(::U2EG_NAMESPACE_NAME::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))
/// Free the memory allocated with OGRE_MALLOC or OGRE_ALLOC_T. Category is required to be restated to ensure the matching policy is used
#	define U2_FREE(ptr, category)			::U2EG_NAMESPACE_NAME::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr)

/// Allocate space for one primitive type, external type or non-virtual type with constructor parameters
#	define U2_NEW_T(T, category)			new (::U2EG_NAMESPACE_NAME::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T
/// Allocate a block of memory for 'count' primitive types - do not use for classes that inherit from AllocatedObject
#	define U2_NEW_ARRAY_T(T, count, category)	::U2EG_NAMESPACE_NAME::constructN(static_cast<T*>(::U2EG_NAMESPACE_NAME::CategorisedAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__)), count) 
/// Free the memory allocated with OGRE_NEW_T. Category is required to be restated to ensure the matching policy is used
#	define U2_DELETE_T(ptr, T, category)		if(ptr){(ptr)->~T(); ::U2EG_NAMESPACE_NAME::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}
/// Free the memory allocated with OGRE_NEW_ARRAY_T. Category is required to be restated to ensure the matching policy is used, count and type to call destructor
#	define U2_DELETE_ARRAY_T(ptr, T, count, category)		if(ptr){for (size_t b = 0; b < count; ++b) { (ptr)[b].~T();} ::U2EG_NAMESPACE_NAME::CategorisedAllocPolicy<category>::deallocateBytes((void*)ptr);}


// aligned allocation
/// Allocate a block of raw memory aligned to SIMD boundaries, and indicate the category of usage
#	define U2_MALLOC_SIMD(bytes, category)          ::U2EG_NAMESPACE_NAME::CategorisedAlignAllocPolicy<category>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)
/// Allocate a block of raw memory aligned to user defined boundaries, and indicate the category of usage
#	define U2_MALLOC_ALIGN(bytes, category, align)  ::U2EG_NAMESPACE_NAME::CategorisedAlignAllocPolicy<category, align>::allocateBytes(bytes, __FILE__, __LINE__, __FUNCTION__)
/// Allocate a block of memory for a primitive type aligned to SIMD boundaries, and indicate the category of usage
#	define U2_ALLOC_T_SIMD(T, count, category)      static_cast<T*>(::U2EG_NAMESPACE_NAME::CategorisedAlignAllocPolicy<category>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))
/// Allocate a block of memory for a primitive type aligned to user defined boundaries, and indicate the category of usage
#	define U2_ALLOC_T_ALIGN(T, count, category, align)  static_cast<T*>(::U2EG_NAMESPACE_NAME::CategorisedAlignAllocPolicy<category, align>::allocateBytes(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))
/// Free the memory allocated with either OGRE_MALLOC_SIMD or OGRE_ALLOC_T_SIMD. Category is required to be restated to ensure the matching policy is used
#	define U2_FREE_SIMD(ptr, category)              ::U2EG_NAMESPACE_NAME::CategorisedAlignAllocPolicy<category>::deallocateBytes(ptr)
/// Free the memory allocated with either OGRE_MALLOC_ALIGN or OGRE_ALLOC_T_ALIGN. Category is required to be restated to ensure the matching policy is used
#	define U2_FREE_ALIGN(ptr, category, align)      ::U2EG_NAMESPACE_NAME::CategorisedAlignAllocPolicy<category, align>::deallocateBytes(ptr)


// new / delete for classes deriving from AllocatedObject (alignment determined by per-class policy)
// Also hooks up the file/line/function params
// Can only be used with classes that derive from AllocatedObject since customised new/delete needed
#	define U2_NEW		new (__FILE__, __LINE__, __FUNCTION__)
#	define U2_DELETE	delete

//#	define NEW			new
//#	define DELETE		delete

#else
#endif




#endif